
//Use 'restify' to provide RESTful service
var restify = require('restify');
var fs = require('fs');

// The meta-data of the HTTP server
var httpServer = require('./config/httpServer.json');

// Create HTTP server with required parsers
var server = restify.createServer({
	name : httpServer.name,
	version : httpServer.version,
});

// for SSL
var serverSSL;
if (httpServer.sslEnabled) {
	var serverSSL = restify.createServer({
		name : httpServer.name,
		version : httpServer.version,
		key : fs.readFileSync(httpServer.sslKey),
		certificate : fs.readFileSync(httpServer.sslCertificate)
	});
}

server.use(restify.authorizationParser());
// for SSL
if (httpServer.sslEnabled) {
	serverSSL.use(restify.authorizationParser());
}

server.use(restify.dateParser());
// for SSL
if (httpServer.sslEnabled) {
	serverSSL.use(restify.dateParser());
}

server.use(restify.queryParser());
// for SSL
if (httpServer.sslEnabled) {
	serverSSL.use(restify.queryParser());
}

if (httpServer.uploadPath) {
	server.use(restify.bodyParser({
		uploadDir : httpServer.uploadPath
	}));
	// for SSL
	if (httpServer.sslEnabled) {
		serverSSL.use(restify.bodyParser({
			uploadDir : httpServer.uploadPath
		}));
	}
}

server.use(restify.throttle({
	burst : httpServer.throttleBurst,
	rate : httpServer.throttleRate,
	ip : true, // xff is another choice
	overrides : {
		'127.0.0.1' : {
			rate : 0, // unlimited
			burst : 0
		}
	}
}));
// for SSL
if (httpServer.sslEnabled) {
	serverSSL.use(restify.throttle({
		burst : httpServer.throttleBurst,
		rate : httpServer.throttleRate,
		ip : true, // xff is another choice
		overrides : {
			'127.0.0.1' : {
				rate : 0, // unlimited
				burst : 0
			}
		}
	}));
}

if (httpServer.authorization) {
	function authorization(req, res, next) {
		console.log('user name=%s', req.username);

		if (req.authorization.basic) {
			console.log('password=%s', req.authorization.basic.password);
		}
		// return next(new restify.NotAuthorizedError());
		return next();
	}

	// refine following function if authenticate is enabled
	server.use(authorization);
	// for SSL
	if (httpServer.sslEnabled) {
		serverSSL.use(authorization);
	}
}
if (httpServer.logEnable) {
	var bunyan = require('restify/node_modules/bunyan');

	var log = bunyan.createLogger({
		name : 'my_restify_application',
		level : process.env.LOG_LEVEL || 'info',
		stream : process.stdout,
		serializers : bunyan.stdSerializers
	});

	server.on('after', restify.auditLogger({
		log : log
	}));
	// for SSL
	if (httpServer.sslEnabled) {
		serverSSL.on('after', restify.auditLogger({
			log : log
		}));
	}
}

function bindServiceList(service, serviceList) {
	serviceList.unshift(service.path);

	if (!service.useSSL) {
		server[service.method].apply(server, serviceList);
	} else {
		serverSSL[service.method].apply(server, serviceList);
	}
}

function bindServiceFile(serviceID, service, serviceImplFile) {
	var serviceImplFile = require(serviceImplFile);
	var serviceMappings = serviceImplFile.mappings;
	if (serviceMappings) {
		var serviceFunction = serviceMappings[serviceID];
		if (serviceFunction) {
			if (!service.useSSL) {
				server[service.method](service.path, serviceFunction);
			} else {
				serverSSL[service.method](service.path, serviceFunction);
			}
		}

	} else {
		var serviceImpls = serviceImplFile.services;
		for ( var i in serviceImpls) {
			serviceImpl = serviceImpls[i];
			if (serviceID == serviceImpl.name) {
				if (!service.useSSL) {
					server[service.method](service.path, serviceImpl);
				} else {
					serverSSL[service.method](service.path, serviceImpl);
				}
				break;
			}
		}
	}
}

/*
 * bind service implementations to service definitions
 */
function bindServices(servicesConfig, serviceBindingsConfig) {
	// The meta-data of the RESTful services
	var services = require(servicesConfig);
	// The binding configuration of the service definition and service
	// implementation
	var serviceBindings = require(serviceBindingsConfig);

	for ( var serviceID in services) {
		var service = services[serviceID];
		var serviceBinding = serviceBindings[serviceID];
		if (!serviceBinding) {
			serviceBinding = serviceBindings['*'];
		}

		if ((typeof (serviceBinding)) == "object") {
			var serviceList = [];
			for ( var i in serviceBinding) {
				var serviceImplFile = serviceBinding[i];
				var objServiceImplFile = require(serviceImplFile);
				var serviceMappings = objServiceImplFile.mappings;
				if (serviceMappings) {
					var serviceFunction = serviceMappings[serviceID];
					if (serviceFunction) {
						serviceList.push(serviceFunction);
					}

				} else {
					var serviceImpls = objServiceImplFile.services;
					for ( var i in serviceImpls) {
						serviceImpl = serviceImpls[i];
						if (serviceID == serviceImpl.name) {
							serviceList.push(serviceImpl);
							break;
						}
					}
				}
			}
			bindServiceList(service, serviceList);
		} else {
			var serviceImplFile = serviceBinding;
			bindServiceFile(serviceID, service, serviceImplFile);
		}
	}
}
bindServices('./config/services.json', './config/serviceBindings.json');
bindServices('./config/Mservices.json', './config/MserviceBindings.json');
// Start HTTP server
function _serverStarted() {
	console.log('%s listening at %s', server.name, server.url);
}
if (httpServer.host) {
	server.listen(httpServer.port, httpServer.host, _serverStarted);
} else {
	server.listen(httpServer.port, _serverStarted);
}
// for SSL
if (httpServer.sslEnabled) {
	function _serverSSLStarted() {
		console.log('%s listening at %s', serverSSL.name, serverSSL.url);
	}
	if (httpServer.hostSSL) {
		serverSSL.listen(httpServer.portSSL, httpServer.hostSSL,
				_serverSSLStarted);
	} else {
		serverSSL.listen(httpServer.portSSL, _serverSSLStarted);
	}
}

//require("./test/script/createDriver").createDriver();
